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 dd40d489d5 Add support for setting Session properties via setProperty
dd40d489d5 is described below

commit dd40d489d5c4a9db9bc8d7b550fcb632e0fcde7d
Author: James Bognar <[email protected]>
AuthorDate: Sat Apr 4 11:39:01 2026 -0400

    Add support for setting Session properties via setProperty
---
 .../org/apache/juneau/assertions/Assertion.java    |   3 +-
 .../commons/conversion/ConversionFinder.java       |   3 +
 .../main/java/org/apache/juneau/config/Config.java |   3 +-
 .../apache/juneau/jena/RdfSerializerSession.java   |  23 ++-
 .../main/java/org/apache/juneau/BeanContext.java   |  12 +-
 .../main/java/org/apache/juneau/BeanSession.java   |  20 ++-
 .../src/main/java/org/apache/juneau/ClassMeta.java |   7 +-
 .../java/org/apache/juneau/ContextSession.java     |  40 ++++-
 .../org/apache/juneau/parser/ParserSession.java    |  21 ++-
 .../apache/juneau/parser/ReaderParserSession.java  |  17 +-
 .../juneau/serializer/SerializerSession.java       |  38 ++++-
 .../juneau/serializer/WriterSerializerSession.java |  20 ++-
 .../juneau/examples/rest/ContentComboTestBase.java |   6 +-
 .../juneau/examples/rest/RootResourcesTest.java    |   3 +
 .../juneau/examples/rest/SamplesMicroservice.java  |   1 +
 .../apache/juneau/microservice/Microservice.java   |   6 +
 .../microservice/resources/DirectoryResource.java  |   3 +-
 .../juneau/microservice/resources/LogParser.java   |   3 +
 .../microservice/resources/LogsResource.java       |   3 +
 .../rest/client/BasicHttpEntityRequestBase.java    |   3 +
 .../juneau/rest/client/BasicHttpRequestBase.java   |   3 +
 .../juneau/rest/client/BasicRestCallHandler.java   |   3 +
 .../apache/juneau/rest/client/ResponseHeader.java  |   3 +
 .../juneau/rest/client/ResponseStatusLine.java     |   3 +
 .../org/apache/juneau/rest/client/RestClient.java  |   6 +-
 .../org/apache/juneau/rest/mock/MockConsole.java   |   3 +
 .../apache/juneau/rest/mock/MockRestClient.java    |   3 +
 .../juneau/rest/mock/MockServletRequest.java       |   3 +
 .../juneau/rest/mock/MockServletResponse.java      |   3 +-
 .../java/org/apache/juneau/rest/RestContext.java   |   1 +
 .../java/org/apache/juneau/rest/RestRequest.java   |   1 +
 .../org/apache/juneau/rest/guard/RoleMatcher.java  |   3 +
 .../rest/swagger/BasicSwaggerProviderSession.java  |   3 +-
 .../rest/util/BoundedServletInputStream.java       |   3 +
 .../rest/util/CachingHttpServletResponse.java      |   3 +
 .../rest/util/FinishableServletOutputStream.java   |   3 +
 .../server/config/repository/GitControl.java       |   1 +
 .../org/apache/juneau/ContextSession_Test.java     | 171 +++++++++++++++++++++
 .../juneau/commons/reflect/ParameterInfo_Test.java |   1 +
 39 files changed, 397 insertions(+), 58 deletions(-)

diff --git 
a/juneau-core/juneau-assertions/src/main/java/org/apache/juneau/assertions/Assertion.java
 
b/juneau-core/juneau-assertions/src/main/java/org/apache/juneau/assertions/Assertion.java
index 03a96688d7..48a5257508 100644
--- 
a/juneau-core/juneau-assertions/src/main/java/org/apache/juneau/assertions/Assertion.java
+++ 
b/juneau-core/juneau-assertions/src/main/java/org/apache/juneau/assertions/Assertion.java
@@ -60,7 +60,8 @@ import org.apache.juneau.cp.*;
  */
 @SuppressWarnings({
        "java:S115", // Constants use UPPER_snakeCase convention (e.g., 
MSG_parameterCannotBeNull); System.err/out usage is intentional for assertion 
error output
-       "java:S106" // System.out/err usage acceptable for assertion output
+       "java:S106", // System.out/err usage acceptable for assertion output
+       "resource" // out field assigned to System.err which is a JVM-managed 
singleton not owned by this class
 })
 public class Assertion {
 
diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/ConversionFinder.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/ConversionFinder.java
index 111367b16a..8c75a776a0 100644
--- 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/ConversionFinder.java
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/conversion/ConversionFinder.java
@@ -54,5 +54,8 @@ public interface ConversionFinder {
         * @param outType The output type class.
         * @return A {@link Conversion} function, or <jk>null</jk> if no 
conversion is available.
         */
+       @SuppressWarnings({
+               "java:S1452" // Wildcards unavoidable; concrete I/O types are 
only known at runtime
+       })
        Conversion<?,?> findConversion(Class<?> inType, Class<?> outType);
 }
diff --git 
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java 
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
index 3d3ab458d5..851a0f818d 100644
--- 
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
+++ 
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
@@ -56,7 +56,8 @@ import org.apache.juneau.svl.*;
  * </ul>
  */
 @SuppressWarnings({
-       "java:S115" // Constants use UPPER_snakeCase convention
+       "java:S115", // Constants use UPPER_snakeCase convention
+       "resource" // ConfigStore and other Closeable fields are owned by the 
caller; lifecycle managed externally
 })
 public class Config extends Context implements ConfigEventListener {
 
diff --git 
a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
 
b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
index 634ea68dcd..a6fe3cebb3 100644
--- 
a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
+++ 
b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
@@ -58,6 +58,7 @@ import org.apache.jena.riot.*;
        "rawtypes", // Raw types necessary for generic type handling
        "unchecked", // Type erasure requires unchecked casts
        "java:S115", // Constants use UPPER_snakeCase naming convention
+       "java:S2176" // Inheritance depth exceeds 5; necessary to participate 
in the serializer session hierarchy
 })
 public class RdfSerializerSession extends WriterSerializerSession {
 
@@ -304,7 +305,7 @@ public class RdfSerializerSession extends 
WriterSerializerSession {
        }
 
        private String getUri(Object uri, Object uri2) {
-               var s = (String)null;
+               String s = null;
                if (nn(uri))
                        s = uri.toString();
                if ((s == null || s.isEmpty()) && nn(uri2))
@@ -320,11 +321,10 @@ public class RdfSerializerSession extends 
WriterSerializerSession {
        private RDFNode serializeAnything(Object o, boolean isURI, ClassMeta<?> 
eType, String attrName, BeanPropertyMeta bpm, Resource parentResource) throws 
SerializeException {
                var m = model;
 
-               var aType = (ClassMeta<?>)null;       // The actual type
-               var wType = (ClassMeta<?>)null;       // The wrapped type
-               ClassMeta<?> sType = object();   // The serialized type
+               ClassMeta<?> wType = null;            // The wrapped type
+               ClassMeta<?> sType;                   // The serialized type
 
-               aType = push2(attrName, o, eType);
+               var aType = push2(attrName, o, eType);  // The actual type
 
                if (eType == null)
                        eType = object();
@@ -368,7 +368,7 @@ public class RdfSerializerSession extends 
WriterSerializerSession {
 
                var typeName = getBeanTypeName(this, eType, aType, bpm);
 
-               var n = (RDFNode)null;
+               RDFNode n = null;
 
                if (o == null || sType.isChar() && ((Character)o).charValue() 
== 0) {
                        if (nn(bpm)) {
@@ -398,7 +398,7 @@ public class RdfSerializerSession extends 
WriterSerializerSession {
 
                } else if (sType.isMap() || (nn(wType) && wType.isMap())) {
                        if (o instanceof BeanMap o2) {
-                               var uri = (Object)null;
+                               Object uri = null;
                                var rbm = getRdfBeanMeta(o2.getMeta());
                                if (rbm.hasBeanUri())
                                        uri = rbm.getBeanUriProperty().get(o2, 
null);
@@ -413,7 +413,7 @@ public class RdfSerializerSession extends 
WriterSerializerSession {
 
                } else if (sType.isBean()) {
                        var bm = toBeanMap(o);
-                       var uri = (Object)null;
+                       Object uri = null;
                        RdfBeanMeta rbm = getRdfBeanMeta(bm.getMeta());
                        if (rbm.hasBeanUri())
                                uri = rbm.getBeanUriProperty().get(bm, null);
@@ -466,9 +466,7 @@ public class RdfSerializerSession extends 
WriterSerializerSession {
                }
 
                var checkNull = (Predicate<Object>)(x -> isKeepNullProperties() 
|| nn(x));
-               m.forEachValue(checkNull, (pMeta, key, value, thrown) -> {
-                       l.add(new BeanPropertyValue(pMeta, key, value, thrown));
-               });
+               m.forEachValue(checkNull, (pMeta, key, value, thrown) -> 
l.add(new BeanPropertyValue(pMeta, key, value, thrown)));
 
                Collections.reverse(l);
                l.forEach(x -> {
@@ -564,14 +562,13 @@ public class RdfSerializerSession extends 
WriterSerializerSession {
        @Override /* Overridden from Serializer */
        protected void doSerialize(SerializerPipe out, Object o) throws 
SerializeException {
 
-               var r = (Resource)null;
-
                var cm = getClassMetaForObject(o);
                if (isLooseCollections() && nn(cm) && cm.isCollectionOrArray()) 
{
                        Collection c = cm.isCollection() ? (Collection)o : 
toList(cm.inner(), o);
                        forEachEntry(c, x -> serializeAnything(x, false, 
object(), "root", null, null));
                } else {
                        RDFNode n = serializeAnything(o, false, 
getExpectedRootType(o), "root", null, null);
+                       Resource r;
                        if (n.isLiteral()) {
                                r = model.createResource();
                                r.addProperty(pValue, n);
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
index 8274f39b8d..129f7022ef 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
@@ -4916,18 +4916,10 @@ public class BeanContext extends Context implements 
ConversionFinder {
                if (! (o instanceof ParameterizedType)) {
                        while (nn(c)) {
                                o = c.getGenericSuperclass();
+                               if (!(o instanceof ParameterizedType))
+                                       o = 
Arrays.stream(c.getGenericInterfaces()).filter(t -> t instanceof 
ParameterizedType).findFirst().orElse(null);
                                if (o instanceof ParameterizedType)
                                        break;
-                               boolean found = false;
-                               for (var t : c.getGenericInterfaces()) {
-                                       o = t;
-                                       if (o instanceof ParameterizedType) {
-                                               found = true;
-                                               break;
-                                       }
-                               }
-                               if (found)
-                                       break;
                                c = c.getSuperclass();
                        }
                }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
index 92268c6abd..65acde4c7d 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
@@ -58,6 +58,9 @@ public class BeanSession extends ContextSession implements 
ConverterSession {
        private static final String PROP_locale = "locale";
        private static final String PROP_mediaType = "mediaType";
        private static final String PROP_timeZone = "timeZone";
+       private static final String PROP_BeanSession_locale = 
"BeanSession.locale";
+       private static final String PROP_BeanSession_mediaType = 
"BeanSession.mediaType";
+       private static final String PROP_BeanSession_timeZone = 
"BeanSession.timeZone";
 
        // Argument name constants for assertArgNotNull
        private static final String ARG_ctx = "ctx";
@@ -180,8 +183,21 @@ public class BeanSession extends ContextSession implements 
ConverterSession {
 
                @Override /* Overridden from Builder */
                public Builder property(String key, Object value) {
-                       super.property(key, value);
-                       return this;
+                       if (key == null) {
+                               super.property(key, value);  // delegates 
null-key validation to base class
+                               return this;
+                       }
+                       switch (key) {
+                               case PROP_locale, PROP_BeanSession_locale:
+                                       return locale(cvt(value, Locale.class));
+                               case PROP_mediaType, PROP_BeanSession_mediaType:
+                                       return mediaType(cvt(value, 
MediaType.class));
+                               case PROP_timeZone, PROP_BeanSession_timeZone:
+                                       return timeZone(cvt(value, 
TimeZone.class));
+                               default:
+                                       super.property(key, value);
+                                       return this;
+                       }
                }
 
                /**
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
index 1d8cb95120..5b367e3b49 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
@@ -650,6 +650,9 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
         *
         * @return An empty optional, or <jk>null</jk> if this isn't an 
optional.
         */
+       @SuppressWarnings({
+               "java:S2789" // null intentionally signals "not an Optional 
type"; callers check for null
+       })
        public Optional<?> getOptionalDefault() {
                if (isOptional())
                        return opt(getElementType().getOptionalDefault());
@@ -869,7 +872,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                // array conversions from element types, which can produce 
false positives here.
                if (inner().isArray() && c.isArray())
                        return false;
-               // Exclude Collections and Maps: BeanSession handles 
collection/map conversion directly;
+               // Exclude Collections and Maps — BeanSession handles 
collection/map conversion directly.
                // BasicConverter's generic conversions produce false positives 
that Mutaters never did.
                if (Collection.class.isAssignableFrom(inner()) || 
Map.class.isAssignableFrom(inner()))
                        return false;
@@ -907,7 +910,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
                // array conversions from element types, which can produce 
false positives here.
                if (inner().isArray() && c.isArray())
                        return false;
-               // Exclude Collection/Map targets: BeanSession handles 
collection/map conversion directly;
+               // Exclude Collection/Map targets — BeanSession handles 
collection/map conversion directly.
                // BasicConverter's generic conversions produce false positives 
that Mutaters never did.
                if (Collection.class.isAssignableFrom(c) || 
Map.class.isAssignableFrom(c))
                        return false;
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ContextSession.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ContextSession.java
index f1c49496b2..151cf03d6f 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ContextSession.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ContextSession.java
@@ -28,6 +28,7 @@ import java.util.*;
 import java.util.function.*;
 
 import org.apache.juneau.commons.collections.*;
+import org.apache.juneau.commons.conversion.*;
 import org.apache.juneau.commons.function.*;
 import org.apache.juneau.commons.reflect.*;
 
@@ -46,6 +47,7 @@ public abstract class ContextSession {
 
        // Property name constants
        private static final String PROP_debug = "debug";
+       private static final String PROP_ContextSession_debug = 
"ContextSession.debug";
 
        // Argument name constants for assertArgNotNull
        private static final String ARG_ctx = "ctx";
@@ -66,6 +68,18 @@ public abstract class ContextSession {
                private Context ctx;
                private Memoizer<LinkedHashMap<String,Object>> properties;
 
+               /**
+                * Convenience method for converting values using {@link 
BasicConverter}.
+                *
+                * @param <T> The target type.
+                * @param value The value to convert.
+                * @param type The target class.
+                * @return The converted value.
+                */
+               protected static <T> T cvt(Object value, Class<T> type) {
+                       return BasicConverter.INSTANCE.to(value, null, null, 
type);
+               }
+
                /**
                 * Constructor.
                 *
@@ -141,28 +155,38 @@ public abstract class ContextSession {
                public Builder properties(Map<String,Object> value) {
                        assertArgNotNull(ARG_value, value);
                        properties.reset();
-                       properties.get().putAll(value);
+                       value.forEach(this::property);
                        return this;
                }
 
                /**
                 * Adds a property to this session.
                 *
+                * <p>
+                * If the key matches a known session property (e.g. 
<js>"debug"</js> or <js>"ContextSession.debug"</js>),
+                * the value is converted via {@link BasicConverter} and routed 
to the corresponding typed setter.
+                * Unknown keys are stored in the raw session properties map.
+                *
                 * @param key The property key.
                 *      <br>Cannot be <jk>null</jk>.
                 * @param value The property value.
-                *      <br>Can be <jk>null</jk> (removes the property).
+                *      <br>Can be <jk>null</jk> (resets typed properties to 
their default; removes raw properties).
                 * @return This object.
                 */
                public Builder property(String key, Object value) {
                        assertArgNotNull(ARG_key, key);
-                       var map = properties.get();
-                       if (value == null) {
-                               map.remove(key);
-                       } else {
-                               map.put(key, value);
+                       switch (key) {
+                               case PROP_debug, PROP_ContextSession_debug:
+                                       return debug(cvt(value, Boolean.class));
+                               default:
+                                       var map = properties.get();
+                                       if (value == null) {
+                                               map.remove(key);
+                                       } else {
+                                               map.put(key, value);
+                                       }
+                                       return this;
                        }
-                       return this;
                }
 
                /**
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java
index db8eaf85b4..d9056bbbba 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java
@@ -61,6 +61,10 @@ public class ParserSession extends BeanSession {
        private static final String PROP_javaMethod = "javaMethod";
        private static final String PROP_listener = "listener";
        private static final String PROP_outer = "outer";
+       private static final String PROP_schema = "schema";
+       private static final String PROP_ParserSession_javaMethod = 
"ParserSession.javaMethod";
+       private static final String PROP_ParserSession_outer = 
"ParserSession.outer";
+       private static final String PROP_ParserSession_schema = 
"ParserSession.schema";
 
        // Argument name constants for assertArgNotNull
        private static final String ARG_ctx = "ctx";
@@ -157,8 +161,21 @@ public class ParserSession extends BeanSession {
 
                @Override /* Overridden from Builder */
                public Builder property(String key, Object value) {
-                       super.property(key, value);
-                       return this;
+                       if (key == null) {
+                               super.property(key, value);
+                               return this;
+                       }
+                       switch (key) {
+                               case PROP_javaMethod, 
PROP_ParserSession_javaMethod:
+                                       return javaMethod(cvt(value, 
Method.class));
+                               case PROP_outer, PROP_ParserSession_outer:
+                                       return outer(value);
+                               case PROP_schema, PROP_ParserSession_schema:
+                                       return schema(cvt(value, 
HttpPartSchema.class));
+                               default:
+                                       super.property(key, value);
+                                       return this;
+                       }
                }
 
                /**
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ReaderParserSession.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ReaderParserSession.java
index 445107ea2b..df4b3f1a46 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ReaderParserSession.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ReaderParserSession.java
@@ -47,6 +47,8 @@ public class ReaderParserSession extends ParserSession {
        // Property name constants
        private static final String PROP_fileCharset = "fileCharset";
        private static final String PROP_streamCharset = "streamCharset";
+       private static final String PROP_ReaderParserSession_fileCharset = 
"ReaderParserSession.fileCharset";
+       private static final String PROP_ReaderParserSession_streamCharset = 
"ReaderParserSession.streamCharset";
 
        // Argument name constants for assertArgNotNull
        private static final String ARG_ctx = "ctx";
@@ -150,8 +152,19 @@ public class ReaderParserSession extends ParserSession {
 
                @Override /* Overridden from Builder */
                public Builder property(String key, Object value) {
-                       super.property(key, value);
-                       return this;
+                       if (key == null) {
+                               super.property(key, value);
+                               return this;
+                       }
+                       switch (key) {
+                               case PROP_fileCharset, 
PROP_ReaderParserSession_fileCharset:
+                                       return fileCharset(cvt(value, 
Charset.class));
+                               case PROP_streamCharset, 
PROP_ReaderParserSession_streamCharset:
+                                       return streamCharset(cvt(value, 
Charset.class));
+                               default:
+                                       super.property(key, value);
+                                       return this;
+                       }
                }
 
                @Override /* Overridden from Builder */
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSession.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSession.java
index 461f4718b0..b37102ce25 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSession.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSession.java
@@ -70,16 +70,23 @@ import org.apache.juneau.utils.Iso8601Utils;
 public class SerializerSession extends BeanTraverseSession {
 
        // Property name constants
+       private static final String PROP_javaMethod = "javaMethod";
+       private static final String PROP_resolver = "resolver";
+       private static final String PROP_schema = "schema";
+       private static final String PROP_uriContext = "uriContext";
        private static final String PROP_uriResolver = "uriResolver";
-
-       // Argument name constants for assertArgNotNull
-       private static final String ARG_ctx = "ctx";
+       private static final String PROP_SerializerSession_javaMethod = 
"SerializerSession.javaMethod";
+       private static final String PROP_SerializerSession_resolver = 
"SerializerSession.resolver";
+       private static final String PROP_SerializerSession_schema = 
"SerializerSession.schema";
+       private static final String PROP_SerializerSession_uriContext = 
"SerializerSession.uriContext";
 
        /**
         * Builder class.
         */
        public static class Builder extends BeanTraverseSession.Builder {
 
+               private static final String ARG_ctx = "ctx";
+
                private HttpPartSchema schema;
                private Method javaMethod;
                private Serializer ctx;
@@ -156,8 +163,23 @@ public class SerializerSession extends BeanTraverseSession 
{
 
                @Override /* Overridden from Builder */
                public Builder property(String key, Object value) {
-                       super.property(key, value);
-                       return this;
+                       if (key == null) {
+                               super.property(key, value);
+                               return this;
+                       }
+                       switch (key) {
+                               case PROP_javaMethod, 
PROP_SerializerSession_javaMethod:
+                                       return javaMethod(cvt(value, 
Method.class));
+                               case PROP_resolver, 
PROP_SerializerSession_resolver:
+                                       return resolver(cvt(value, 
VarResolverSession.class));
+                               case PROP_schema, PROP_SerializerSession_schema:
+                                       return schema(cvt(value, 
HttpPartSchema.class));
+                               case PROP_uriContext, 
PROP_SerializerSession_uriContext:
+                                       return uriContext(cvt(value, 
UriContext.class));
+                               default:
+                                       super.property(key, value);
+                                       return this;
+                       }
                }
 
                /**
@@ -255,7 +277,7 @@ public class SerializerSession extends BeanTraverseSession {
         * @return A new builder.
         */
        public static Builder create(Serializer ctx) {
-               return new Builder(assertArgNotNull(ARG_ctx, ctx));
+               return new Builder(assertArgNotNull("ctx", ctx));
        }
 
        /**
@@ -478,8 +500,8 @@ public class SerializerSession extends BeanTraverseSession {
         * @return A new list containing all elements.
         * @since 9.2.1
         */
-       public final List<?> toListFromStreamable(Object o, ClassMeta<?> type) {
-               var list = new ArrayList<>();
+       public final List<Object> toListFromStreamable(Object o, ClassMeta<?> 
type) {
+               var list = new ArrayList<Object>();
                forEachStreamableEntry(o, type, list::add);
                return list;
        }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializerSession.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializerSession.java
index f05c14b866..4c44251c62 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializerSession.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializerSession.java
@@ -59,6 +59,9 @@ public class WriterSerializerSession extends 
SerializerSession {
        private static final String PROP_fileCharset = "fileCharset";
        private static final String PROP_streamCharset = "streamCharset";
        private static final String PROP_useWhitespace = "useWhitespace";
+       private static final String PROP_WriterSerializerSession_fileCharset = 
"WriterSerializerSession.fileCharset";
+       private static final String PROP_WriterSerializerSession_streamCharset 
= "WriterSerializerSession.streamCharset";
+       private static final String PROP_WriterSerializerSession_useWhitespace 
= "WriterSerializerSession.useWhitespace";
 
        // Argument name constants for assertArgNotNull
        private static final String ARG_ctx = "ctx";
@@ -159,8 +162,21 @@ public class WriterSerializerSession extends 
SerializerSession {
 
                @Override /* Overridden from Builder */
                public Builder property(String key, Object value) {
-                       super.property(key, value);
-                       return this;
+                       if (key == null) {
+                               super.property(key, value);
+                               return this;
+                       }
+                       switch (key) {
+                               case PROP_fileCharset, 
PROP_WriterSerializerSession_fileCharset:
+                                       return fileCharset(cvt(value, 
Charset.class));
+                               case PROP_streamCharset, 
PROP_WriterSerializerSession_streamCharset:
+                                       return streamCharset(cvt(value, 
Charset.class));
+                               case PROP_useWhitespace, 
PROP_WriterSerializerSession_useWhitespace:
+                                       return useWhitespace(cvt(value, 
Boolean.class));
+                               default:
+                                       super.property(key, value);
+                                       return this;
+                       }
                }
 
                @Override /* Overridden from Builder */
diff --git 
a/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/ContentComboTestBase.java
 
b/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/ContentComboTestBase.java
index 927469470d..ea83e6b59c 100644
--- 
a/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/ContentComboTestBase.java
+++ 
b/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/ContentComboTestBase.java
@@ -42,7 +42,8 @@ import org.junit.*;
 @FixMethodOrder(NAME_ASCENDING)
 @Ignore("Base class for parameterized tests - not meant to be run directly")
 @SuppressWarnings({
-       "java:S3577" // Class name ends with "TestBase" to indicate it's a base 
class, not a test class itself
+       "java:S3577", // Class name ends with "TestBase" to indicate it's a 
base class, not a test class itself
+       "resource" // RestClient lifecycle managed via the clients map and 
tearDown(); fluent API chains consume responses internally
 })
 public class ContentComboTestBase extends RestTestcase {
 
@@ -64,7 +65,8 @@ public class ContentComboTestBase extends RestTestcase {
                };
        }
 
-       protected RestClient getClient(String label, Serializer serializer, 
Parser parser, Consumer<RestClient.Builder>...postApply) {
+       @SafeVarargs
+       protected final RestClient getClient(String label, Serializer 
serializer, Parser parser, Consumer<RestClient.Builder>...postApply) {
                if (! clients.containsKey(label)) {
                        var b = SamplesMicroservice.client(serializer, parser);
                        for (var c : postApply)
diff --git 
a/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/RootResourcesTest.java
 
b/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/RootResourcesTest.java
index ebd152a98f..70295da91d 100644
--- 
a/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/RootResourcesTest.java
+++ 
b/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/RootResourcesTest.java
@@ -27,6 +27,9 @@ import org.apache.juneau.rest.beans.*;
 import org.apache.juneau.rest.client.*;
 import org.junit.*;
 
+@SuppressWarnings({
+       "resource" // RestClient lifecycle managed by SamplesMicroservice; 
fluent API chains consume and close responses internally
+})
 @FixMethodOrder(NAME_ASCENDING)
 public class RootResourcesTest extends RestTestcase {
 
diff --git 
a/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/SamplesMicroservice.java
 
b/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/SamplesMicroservice.java
index 7e3cf2919b..d6e5f2ce53 100644
--- 
a/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/SamplesMicroservice.java
+++ 
b/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/SamplesMicroservice.java
@@ -27,6 +27,7 @@ import org.apache.juneau.serializer.*;
 /**
  * Utility class for starting up the examples microservice.
  */
+@SuppressWarnings("resource")
 public class SamplesMicroservice {
        static volatile JettyMicroservice microservice;
        static URI microserviceURI;
diff --git 
a/juneau-microservice/juneau-microservice-core/src/main/java/org/apache/juneau/microservice/Microservice.java
 
b/juneau-microservice/juneau-microservice-core/src/main/java/org/apache/juneau/microservice/Microservice.java
index eb7bea60d9..b89008ff99 100755
--- 
a/juneau-microservice/juneau-microservice-core/src/main/java/org/apache/juneau/microservice/Microservice.java
+++ 
b/juneau-microservice/juneau-microservice-core/src/main/java/org/apache/juneau/microservice/Microservice.java
@@ -95,11 +95,17 @@ import org.apache.juneau.utils.*;
 
  * </ul>
  */
+@SuppressWarnings({
+       "resource" // consoleReader and consoleWriter are backed by system 
streams or caller-provided streams; lifecycle managed by stop()
+})
 public class Microservice implements ConfigEventListener {
 
        /**
         * Builder class.
         */
+       @SuppressWarnings({
+               "resource" // configStore, consoleReader, consoleWriter are 
passed in by the caller or assigned to system streams; lifecycle managed 
externally
+       })
        public static class Builder {
 
                Args args;
diff --git 
a/juneau-microservice/juneau-microservice-core/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java
 
b/juneau-microservice/juneau-microservice-core/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java
index 4529c3254f..fd978341ba 100755
--- 
a/juneau-microservice/juneau-microservice-core/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java
+++ 
b/juneau-microservice/juneau-microservice-core/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java
@@ -79,7 +79,8 @@ import org.apache.juneau.rest.servlet.*;
 )
 @HtmlConfig(uriAnchorText="PROPERTY_NAME")
 @SuppressWarnings({
-       "java:S115" // Constants use UPPER_snakeCase convention (e.g., 
DIRECTORY_RESOURCE_rootDir)
+       "java:S115", // Constants use UPPER_snakeCase convention (e.g., 
DIRECTORY_RESOURCE_rootDir)
+       "resource" // Streams returned to servlet container; lifecycle managed 
by the container
 })
 public class DirectoryResource extends BasicRestServlet {
 
diff --git 
a/juneau-microservice/juneau-microservice-core/src/main/java/org/apache/juneau/microservice/resources/LogParser.java
 
b/juneau-microservice/juneau-microservice-core/src/main/java/org/apache/juneau/microservice/resources/LogParser.java
index 58b5967d23..446850f329 100644
--- 
a/juneau-microservice/juneau-microservice-core/src/main/java/org/apache/juneau/microservice/resources/LogParser.java
+++ 
b/juneau-microservice/juneau-microservice-core/src/main/java/org/apache/juneau/microservice/resources/LogParser.java
@@ -33,6 +33,9 @@ import java.util.regex.*;
  * Provides the capability of returning splices of log files based on dates 
and filtering based on thread and logger
  * names.
  */
+@SuppressWarnings({
+       "resource" // br is closed via this class's close() method
+})
 public class LogParser implements Iterable<LogParser.Entry>, Closeable {
 
        /**
diff --git 
a/juneau-microservice/juneau-microservice-core/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java
 
b/juneau-microservice/juneau-microservice-core/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java
index 4eced507d1..8a8bb6f89c 100644
--- 
a/juneau-microservice/juneau-microservice-core/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java
+++ 
b/juneau-microservice/juneau-microservice-core/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java
@@ -48,6 +48,9 @@ import org.apache.juneau.rest.servlet.*;
        allowedMethodParams="*"
 )
 @HtmlConfig(uriAnchorText="PROPERTY_NAME")
+@SuppressWarnings({
+       "resource" // Streams and parsers returned to servlet container or 
caller; lifecycle managed externally
+})
 public class LogsResource extends BasicRestServlet {
 
        /** File action link. */
diff --git 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/BasicHttpEntityRequestBase.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/BasicHttpEntityRequestBase.java
index 10a15877d7..31a9a43c0f 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/BasicHttpEntityRequestBase.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/BasicHttpEntityRequestBase.java
@@ -25,6 +25,9 @@ import org.apache.http.client.methods.*;
  *     <li class='link'><a class="doclink" 
href="https://juneau.apache.org/docs/topics/JuneauRestClientBasics";>juneau-rest-client
 Basics</a>
  * </ul>
  */
+@SuppressWarnings({
+       "resource" // restRequest is owned by the RestClient call chain; 
lifecycle managed by the enclosing RestCall
+})
 class BasicHttpEntityRequestBase extends HttpEntityEnclosingRequestBase 
implements RestRequestCreated {
 
        final String method;
diff --git 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/BasicHttpRequestBase.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/BasicHttpRequestBase.java
index 5c87a80bd0..82328b57b0 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/BasicHttpRequestBase.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/BasicHttpRequestBase.java
@@ -25,6 +25,9 @@ import org.apache.http.client.methods.*;
  *     <li class='link'><a class="doclink" 
href="https://juneau.apache.org/docs/topics/JuneauRestClientBasics";>juneau-rest-client
 Basics</a>
  * </ul>
  */
+@SuppressWarnings({
+       "resource" // restRequest is owned by the RestClient call chain; 
lifecycle managed by the enclosing RestCall
+})
 class BasicHttpRequestBase extends HttpRequestBase implements 
RestRequestCreated {
 
        final String method;
diff --git 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/BasicRestCallHandler.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/BasicRestCallHandler.java
index f1726629ec..8ca87c68c3 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/BasicRestCallHandler.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/BasicRestCallHandler.java
@@ -31,6 +31,9 @@ import org.apache.http.protocol.*;
  *     <li class='link'><a class="doclink" 
href="https://juneau.apache.org/docs/topics/JuneauRestClientBasics";>juneau-rest-client
 Basics</a>
  * </ul>
  */
+@SuppressWarnings({
+       "resource" // client is passed in by the caller and owned by the 
RestClient; lifecycle managed externally
+})
 public class BasicRestCallHandler implements RestCallHandler {
 
        private final RestClient client;
diff --git 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/ResponseHeader.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/ResponseHeader.java
index df1db2ea92..9fd6a57350 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/ResponseHeader.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/ResponseHeader.java
@@ -47,6 +47,9 @@ import org.apache.juneau.rest.client.assertion.*;
  *     <li class='link'><a class="doclink" 
href="https://juneau.apache.org/docs/topics/JuneauRestClientBasics";>juneau-rest-client
 Basics</a>
  * </ul>
  */
+@SuppressWarnings({
+       "resource" // request and response are owned by the RestCall that 
created this header; lifecycle managed externally
+})
 public class ResponseHeader extends BasicHeader {
 
        private static final long serialVersionUID = 1L;
diff --git 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/ResponseStatusLine.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/ResponseStatusLine.java
index 6b6467e222..29d4d824ea 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/ResponseStatusLine.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/ResponseStatusLine.java
@@ -26,6 +26,9 @@ import org.apache.juneau.rest.client.assertion.*;
  *     <li class='link'><a class="doclink" 
href="https://juneau.apache.org/docs/topics/JuneauRestClientBasics";>juneau-rest-client
 Basics</a>
  * </ul>
  */
+@SuppressWarnings({
+       "resource" // response is owned by the RestCall that created this 
status line; lifecycle managed externally
+})
 public class ResponseStatusLine implements StatusLine {
 
        private final RestResponse response;
diff --git 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
index f33197eb18..e5a2a49701 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
@@ -6375,7 +6375,8 @@ public class RestClient extends BeanContextable 
implements HttpClient, Closeable
         * @throws RestCallException REST call failed.
         */
        @SuppressWarnings({
-               "java:S3776" // Cognitive complexity acceptable for callback 
parsing state machine
+               "java:S3776", // Cognitive complexity acceptable for callback 
parsing state machine
+               "java:S1854"  // state = S5 is a necessary state machine 
transition; SonarLint false positive
        })
        public RestRequest callback(String callString) throws RestCallException 
{
                callString = emptyIfNull(callString);
@@ -8145,7 +8146,8 @@ public class RestClient extends BeanContextable 
implements HttpClient, Closeable
 
        @SuppressWarnings({
                "java:S3776", // Cognitive complexity acceptable for remote 
execution logic
-               "java:S112"   // throws Exception intentional - 
callback/lifecycle method
+               "java:S112",  // throws Exception intentional - 
callback/lifecycle method
+               "unused"      // interfaceClass unused in this implementation 
but part of the remote execution contract
        })
        Object executeRemote(Class<?> interfaceClass, RestRequest rc, Method 
method, RemoteOperationMeta rom) throws Exception {
                RemoteOperationReturn ror = rom.getReturns();
diff --git 
a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockConsole.java
 
b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockConsole.java
index 9c7c046a75..436f054a2e 100644
--- 
a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockConsole.java
+++ 
b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockConsole.java
@@ -82,6 +82,9 @@ import org.apache.juneau.assertions.*;
  *     <li class='link'><a class="doclink" 
href="https://juneau.apache.org/docs/topics/JuneauRestMockBasics";>juneau-rest-mock
 Basics</a>
  * </ul>
  */
+@SuppressWarnings({
+       "resource" // Stream returned to caller; lifecycle managed by the caller
+})
 public class MockConsole extends PrintStream {
 
        private static final ByteArrayOutputStream baos = new 
ByteArrayOutputStream();
diff --git 
a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockRestClient.java
 
b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockRestClient.java
index a157dfec0e..ee3204f257 100644
--- 
a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockRestClient.java
+++ 
b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockRestClient.java
@@ -246,6 +246,9 @@ import jakarta.servlet.http.*;
  *     <li class='link'><a class="doclink" 
href="https://juneau.apache.org/docs/topics/JuneauRestMockBasics";>juneau-rest-mock
 Basics</a>
  * </ul>
  */
+@SuppressWarnings({
+       "resource" // Builders and requests returned to callers; lifecycle 
managed by the enclosing MockRestClient or test
+})
 public class MockRestClient extends RestClient implements HttpClientConnection 
{
 
        /**
diff --git 
a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java
 
b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java
index 229c920835..182f36bf2d 100644
--- 
a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java
+++ 
b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java
@@ -42,6 +42,9 @@ import jakarta.servlet.http.*;
  *     <li class='link'><a class="doclink" 
href="https://juneau.apache.org/docs/topics/JuneauRestMockBasics";>juneau-rest-mock
 Basics</a>
  * </ul>
  */
+@SuppressWarnings({
+       "resource" // Streams returned to servlet container; lifecycle managed 
by the container
+})
 public class MockServletRequest implements HttpServletRequest {
 
        /**
diff --git 
a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockServletResponse.java
 
b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockServletResponse.java
index 3d446b7304..292193d2b8 100644
--- 
a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockServletResponse.java
+++ 
b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockServletResponse.java
@@ -39,7 +39,8 @@ import jakarta.servlet.http.*;
 */
 @SuppressWarnings({
        "java:S4144", // Identical methods intentional for different test 
scenarios
-       "java:S115" // Constants use UPPER_snakeCase convention (e.g., 
HEADER_ContentType)
+       "java:S115", // Constants use UPPER_snakeCase convention (e.g., 
HEADER_ContentType)
+       "resource" // Streams returned to servlet container; lifecycle managed 
by the container
 })
 public class MockServletResponse implements HttpServletResponse {
 
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index 319c88f381..96640c41a9 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -127,6 +127,7 @@ import jakarta.servlet.http.*;
 @SuppressWarnings({
        "java:S115", // Constants use UPPER_snakeCase convention (e.g., 
PROP_allowContentParam); class has 22 dependencies, acceptable for this core 
REST context class
        "java:S1200", // Class has many dependencies; acceptable for this core 
context class
+       "resource" // Streams and session objects returned to callers; 
lifecycle managed by the servlet container or RestCall
 })
 public class RestContext extends Context {
 
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
index 0a466b5f15..16feb2c4d5 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
@@ -173,6 +173,7 @@ import jakarta.servlet.http.*;
        "unchecked", // Type erasure requires unchecked casts in REST client 
operations
        "unused", // Unused parameters in HttpServletRequest overrides and 
helper methods
        "java:S6539", // Collection.toArray() usage intentional
+       "resource" // Streams returned to servlet container; lifecycle managed 
by the container
 })
 public class RestRequest extends HttpServletRequestWrapper {
 
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/guard/RoleMatcher.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/guard/RoleMatcher.java
index e632460ef6..ba8055cc4d 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/guard/RoleMatcher.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/guard/RoleMatcher.java
@@ -111,6 +111,9 @@ public class RoleMatcher {
 
        abstract static class Exp {
 
+               @SuppressWarnings({
+                       "unused" // set parameter unused in this default no-op 
implementation; subclasses use it
+               })
                void appendTokens(Set<String> set) {}
 
                abstract boolean matches(Set<String> roles);
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/swagger/BasicSwaggerProviderSession.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/swagger/BasicSwaggerProviderSession.java
index d0eb5ae6db..2bc7a5bc8a 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/swagger/BasicSwaggerProviderSession.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/swagger/BasicSwaggerProviderSession.java
@@ -746,7 +746,8 @@ public class BasicSwaggerProviderSession {
        }
 
        @SuppressWarnings({
-               "java:S1172" // Parameter kept to match interface contract
+               "java:S1172", // Parameter kept to match interface contract
+               "unused" // Eclipse: type parameter unused but kept for API 
consistency
        })
        private static void addParamExample(RestOpContext sm, JsonMap piri, 
RestPartType in, Type type) {
 
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/BoundedServletInputStream.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/BoundedServletInputStream.java
index bf4f3c3b2c..77b4d199a4 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/BoundedServletInputStream.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/BoundedServletInputStream.java
@@ -27,6 +27,9 @@ import jakarta.servlet.*;
  * ServletInputStream wrapper around a normal input stream with support for 
limiting input.
  *
  */
+@SuppressWarnings({
+       "resource" // is and sis are servlet-container-managed streams passed 
in by the caller; closed by the container
+})
 public class BoundedServletInputStream extends ServletInputStream {
 
        private final InputStream is;
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/CachingHttpServletResponse.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/CachingHttpServletResponse.java
index 3eab6e8cf2..8b20961f60 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/CachingHttpServletResponse.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/CachingHttpServletResponse.java
@@ -25,6 +25,9 @@ import jakarta.servlet.http.*;
  * Wraps an {@link HttpServletResponse} and caches the output stream in a 
separate buffer for debugging purposes.
  *
  */
+@SuppressWarnings({
+       "resource" // os is a servlet-container-managed stream obtained from 
the wrapped response; closed by the container
+})
 public class CachingHttpServletResponse extends HttpServletResponseWrapper {
 
        /**
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/FinishableServletOutputStream.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/FinishableServletOutputStream.java
index 232fbed574..86673aeeb4 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/FinishableServletOutputStream.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/FinishableServletOutputStream.java
@@ -28,6 +28,9 @@ import jakarta.servlet.*;
  * A wrapped {@link ServletOutputStream} with an added <c>finish()</c> method.
  *
  */
+@SuppressWarnings({
+       "resource" // os and sos are servlet-container-managed streams passed 
in by the caller; closed by the container
+})
 public class FinishableServletOutputStream extends ServletOutputStream 
implements Finishable {
 
        final OutputStream os;
diff --git 
a/juneau-sc/juneau-sc-server/src/main/java/org/apache/juneau/server/config/repository/GitControl.java
 
b/juneau-sc/juneau-sc-server/src/main/java/org/apache/juneau/server/config/repository/GitControl.java
index bd33027e70..54271408df 100644
--- 
a/juneau-sc/juneau-sc-server/src/main/java/org/apache/juneau/server/config/repository/GitControl.java
+++ 
b/juneau-sc/juneau-sc-server/src/main/java/org/apache/juneau/server/config/repository/GitControl.java
@@ -37,6 +37,7 @@ import org.eclipse.jgit.transport.*;
  */
 @SuppressWarnings({
        "unused", // Example/demo class - some fields used only for JGit 
configuration
+       "resource" // localRepo and git are JGit resources opened in the 
constructor; lifecycle managed by this class's operations
 })
 public class GitControl {
 
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/ContextSession_Test.java 
b/juneau-utest/src/test/java/org/apache/juneau/ContextSession_Test.java
index f423f22a23..d6dfeb45c5 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/ContextSession_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/ContextSession_Test.java
@@ -18,6 +18,13 @@ package org.apache.juneau;
 
 import static org.junit.jupiter.api.Assertions.*;
 
+import java.nio.charset.*;
+import java.util.*;
+
+import org.apache.juneau.collections.*;
+import org.apache.juneau.json.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.serializer.*;
 import org.junit.jupiter.api.*;
 
 class ContextSession_Test extends TestBase {
@@ -126,5 +133,169 @@ class ContextSession_Test extends TestBase {
                var session = context.createSession().build();
                assertSame(context, session.getContext());
        }
+
+       
//====================================================================================================
+       // ContextSession.Builder.property() dispatch - typed property keys
+       
//====================================================================================================
+
+       @Nested class E_propertyDispatch extends TestBase {
+
+               // -- ContextSession: debug --
+
+               @Test void e01_debug_shortForm() {
+                       var session = BeanContext.DEFAULT.createSession()
+                               .property("debug", true)
+                               .build();
+                       assertTrue(session.isDebug());
+               }
+
+               @Test void e02_debug_qualifiedForm() {
+                       var session = BeanContext.DEFAULT.createSession()
+                               .property("ContextSession.debug", "true")
+                               .build();
+                       assertTrue(session.isDebug());
+               }
+
+               @Test void e03_debug_nullResetsToDefault() {
+                       var session = BeanContext.DEFAULT.createSession()
+                               .property("debug", null)
+                               .build();
+                       assertEquals(BeanContext.DEFAULT.isDebug(), 
session.isDebug());
+               }
+
+               // -- BeanSession: locale --
+
+               @Test void e04_locale_shortForm_string() {
+                       var session = BeanContext.DEFAULT.createSession()
+                               .property("locale", "fr-FR")
+                               .build();
+                       assertEquals(Locale.forLanguageTag("fr-FR"), 
session.getLocale());
+               }
+
+               @Test void e05_locale_qualifiedForm() {
+                       var session = BeanContext.DEFAULT.createSession()
+                               .property("BeanSession.locale", Locale.GERMAN)
+                               .build();
+                       assertEquals(Locale.GERMAN, session.getLocale());
+               }
+
+               // -- BeanSession: timeZone --
+
+               @Test void e06_timeZone_shortForm_string() {
+                       var session = BeanContext.DEFAULT.createSession()
+                               .property("timeZone", "America/New_York")
+                               .build();
+                       assertEquals(TimeZone.getTimeZone("America/New_York"), 
session.getTimeZone());
+               }
+
+               @Test void e07_timeZone_qualifiedForm() {
+                       var tz = TimeZone.getTimeZone("UTC");
+                       var session = BeanContext.DEFAULT.createSession()
+                               .property("BeanSession.timeZone", tz)
+                               .build();
+                       assertEquals(tz, session.getTimeZone());
+               }
+
+               // -- BeanSession: mediaType --
+
+               @Test void e08_mediaType_shortForm_string() {
+                       var session = BeanContext.DEFAULT.createSession()
+                               .property("mediaType", "application/json")
+                               .build();
+                       assertEquals("application/json", 
session.getMediaType().toString());
+               }
+
+               @Test void e09_mediaType_qualifiedForm() {
+                       var session = BeanContext.DEFAULT.createSession()
+                               .property("BeanSession.mediaType", "text/xml")
+                               .build();
+                       assertEquals("text/xml", 
session.getMediaType().toString());
+               }
+
+               // -- WriterSerializerSession: fileCharset, streamCharset, 
useWhitespace --
+
+               @Test void e10_writerSerializer_fileCharset_shortForm() {
+                       var session = (WriterSerializerSession) 
JsonSerializer.DEFAULT.createSession()
+                               .property("fileCharset", "UTF-16")
+                               .build();
+                       assertEquals(Charset.forName("UTF-16"), 
session.getFileCharset());
+               }
+
+               @Test void e11_writerSerializer_fileCharset_qualifiedForm() {
+                       var session = (WriterSerializerSession) 
JsonSerializer.DEFAULT.createSession()
+                               
.property("WriterSerializerSession.fileCharset", Charset.forName("ISO-8859-1"))
+                               .build();
+                       assertEquals(Charset.forName("ISO-8859-1"), 
session.getFileCharset());
+               }
+
+               @Test void e12_writerSerializer_streamCharset_shortForm() {
+                       var session = (WriterSerializerSession) 
JsonSerializer.DEFAULT.createSession()
+                               .property("streamCharset", "UTF-16")
+                               .build();
+                       assertEquals(Charset.forName("UTF-16"), 
session.getStreamCharset());
+               }
+
+               @Test void e13_writerSerializer_streamCharset_qualifiedForm() {
+                       var session = (WriterSerializerSession) 
JsonSerializer.DEFAULT.createSession()
+                               
.property("WriterSerializerSession.streamCharset", "ISO-8859-1")
+                               .build();
+                       assertEquals(Charset.forName("ISO-8859-1"), 
session.getStreamCharset());
+               }
+
+               // -- ReaderParserSession: fileCharset, streamCharset --
+
+               @Test void e14_readerParser_fileCharset_shortForm() {
+                       var session = (ReaderParserSession) 
JsonParser.DEFAULT.createSession()
+                               .property("fileCharset", "UTF-16")
+                               .build();
+                       assertEquals(Charset.forName("UTF-16"), 
session.getFileCharset());
+               }
+
+               @Test void e15_readerParser_streamCharset_qualifiedForm() {
+                       var session = (ReaderParserSession) 
JsonParser.DEFAULT.createSession()
+                               .property("ReaderParserSession.streamCharset", 
"ISO-8859-1")
+                               .build();
+                       assertEquals(Charset.forName("ISO-8859-1"), 
session.getStreamCharset());
+               }
+
+               // -- properties(Map) delegates to property() --
+
+               @Test void e16_properties_map_dispatchesKnownKeys() {
+                       var session = BeanContext.DEFAULT.createSession()
+                               .properties(JsonMap.of("locale", "de-DE", 
"timeZone", "Europe/Berlin", "unknownKey", "someValue"))
+                               .build();
+                       assertEquals(Locale.forLanguageTag("de-DE"), 
session.getLocale());
+                       assertEquals(TimeZone.getTimeZone("Europe/Berlin"), 
session.getTimeZone());
+                       assertEquals("someValue", 
session.getSessionProperties().get("unknownKey"));
+               }
+
+               @Test void e17_properties_map_resetsPreviousRawProperties() {
+                       var session = BeanContext.DEFAULT.createSession()
+                               .property("rawKey1", "value1")
+                               .properties(JsonMap.of("rawKey2", "value2"))
+                               .build();
+                       // After properties(Map), the raw map was reset so 
rawKey1 should be gone
+                       
assertFalse(session.getSessionProperties().containsKey("rawKey1"));
+                       assertEquals("value2", 
session.getSessionProperties().get("rawKey2"));
+               }
+
+               // -- Unknown keys fall through to the raw properties map --
+
+               @Test void e18_unknownKey_goesToRawMap() {
+                       var session = BeanContext.DEFAULT.createSession()
+                               .property("myCustomKey", "myCustomValue")
+                               .build();
+                       assertEquals("myCustomValue", 
session.getSessionProperties().get("myCustomKey"));
+               }
+
+               // -- Locale inheritance through serializer session chain --
+
+               @Test void e19_locale_dispatchedThroughSerializerChain() {
+                       var session = (WriterSerializerSession) 
JsonSerializer.DEFAULT.createSession()
+                               .property("locale", "ja-JP")
+                               .build();
+                       assertEquals(Locale.forLanguageTag("ja-JP"), 
session.getLocale());
+               }
+       }
 }
 
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ParameterInfo_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ParameterInfo_Test.java
index 76e98d2e5b..2ed377c07c 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ParameterInfo_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/commons/reflect/ParameterInfo_Test.java
@@ -38,6 +38,7 @@ import org.junit.jupiter.api.*;
        "java:S1186", // Empty method body intentional for callback testing
        "java:S116", // Field names use underscores for test data clarity
        "java:S1172", // Unused parameters kept for API consistency or 
framework requirements
+       "java:S3008", // Static field names use underscores for test data 
clarity
 })
 class ParameterInfo_Test extends TestBase {
 

Reply via email to